package zkwrapper

import (
	"errors"
	"github.com/samuel/go-zookeeper/zk"
	"strconv"
	"strings"
	"time"
)

type ZkEventChan <-chan zk.Event

type ZkWrapper struct {
	zkAddr  string
	zconn   *zk.Conn
	session <-chan zk.Event
}

func NewZkWrapper(addr string) (zw *ZkWrapper, e error) {
	zw = new(ZkWrapper)

	addrArray := strings.Split(addr, ",")
	zw.zconn, zw.session, e = zk.Connect(addrArray, 5*time.Second)

	if e != nil {
		return nil, e
	}
	// Wait for connection - avoid to be blocked forever!
	select {
	case <-time.After(10 * time.Second):
		return nil, errors.New("DialTimeout")
	case event := <-zw.session:
		if event.State != zk.StateConnecting {

			return nil, errors.New("Failed to connect ZK")
		}
	}

	zw.zkAddr = addr
	return zw, nil
}

func (zw *ZkWrapper) Close() error {
	if zw.zconn != nil {
		zw.zconn.Close()
	} else {
		return errors.New("null point")
	}
	return nil
}

func (zw *ZkWrapper) CreateDir(path string) error {
	_, err := zw.zconn.Create(path, []byte(""), 0, zk.WorldACL(zk.PermAll))
	return err
}

func (zw *ZkWrapper) AddEphemeralServer(dir string, id int, value string) error {
	dir = dir + "/" + strconv.Itoa(id)
	_, err := zw.zconn.Create(dir, []byte(value), zk.FlagEphemeral, zk.WorldACL(zk.PermAll))
	return err
}

//remove itself from ZK
func (zw *ZkWrapper) RemoveServer(dir string, id int) error {
	return nil
}

func (zw *ZkWrapper) CheckExistingNode(path string) bool {
	exist, _, _ := zw.zconn.Exists(path)
	return exist
}

func (zw *ZkWrapper) SetServerValue(dir string, id int, value string) error {
	dir = dir + "/" + strconv.Itoa(id)
	_, err := zw.zconn.Set(dir, []byte(value), -1)
	return err
}

func (zw *ZkWrapper) GetServerValue(dir string, id int) (value string, e error) {
	dir = dir + "/" + strconv.Itoa(id)
	var valueByte []byte
	valueByte, _, e = zw.zconn.Get(dir)
	value = string(valueByte)
	return
}

func (zw *ZkWrapper) WatchChildren(dir string) (watch ZkEventChan, e error) {
	var w <-chan zk.Event
	_, _, w, e = zw.zconn.ChildrenW(dir)
	watch = ZkEventChan(w)
	return
}
